using Fusion.Frameworks;
using Fusion.Frameworks.Assets;
using Fusion.Hotfix.Mono.LifeCycle;
using Fusion.Utilities.Generics;
using System;
using System.Reflection;
using UnityEngine;

namespace Fusion.Hotfix.Mono
{
    public class DLLMonoBehaviour : MonoBehaviour
    {
        [SerializeField]
        private string classFullName;

        [SerializeField]
        private string monoDataAsset;

        private static string monoDataAssetPrefix = "MonoData/";
        private static string monoDataAssetPath = null;

        private DLLMonoBase monoBase;

        public string MonoDataAsset { get => monoDataAsset; set => monoDataAsset = value; }
        public string ClassFullName { get => classFullName; 
            set 
            { 
                classFullName = value;
                CreateMonoBase();
            } 
        }

        public DLLMonoBase MonoBase { get => monoBase; }

        private void Awake()
        {
            CreateMonoBase();
            monoBase?.Awake();
        }

        private void Start()
        {
            monoBase?.Start();
            GenerateLifeCycles();
        }

        private void OnEnable()
        {
            monoBase?.OnEnable();
        }

        private void OnDisable()
        {
            monoBase?.OnDisable();
        }

        private void CreateMonoBase()
        {
            if (monoBase == null && classFullName != null && classFullName.Trim() != "")
            {
                string monoDataJson = null;
                if (monoDataAsset != null && monoDataAsset.Trim() != "")
                {
                    monoDataAssetPath = monoDataAssetPrefix + monoDataAsset;
                    TextAsset textAsset = AssetsManager.Instance.Load<TextAsset>(monoDataAssetPath);
                    monoDataJson = textAsset.text;
                    AssetsUtility.ReleaseImmediate(monoDataAssetPath);
                }

                monoBase = DLLManager.Instance.Instantiate<DLLMonoBase>(classFullName, this, monoDataJson);
                DLLMonoRecorder dllMonoRecorder = gameObject.GetOrAddComponent<DLLMonoRecorder>();
                dllMonoRecorder.AddMono(classFullName, monoBase);
            }
        }

        private OrderDictionary<string, DLLMonoLifeCycle> lifeCycleMap = new OrderDictionary<string, DLLMonoLifeCycle>();
        public void Enable(bool enabled)
        {
            this.enabled = enabled;
            int count = lifeCycleMap.Count;
            for (int index = 0; index < count; index++)
            { 
                lifeCycleMap.Get(index).enabled = enabled;
            }
        }

        private void GenerateLifeCycles()
        {
            if (monoBase == null)
            {
                return;
            }

            OrderDictionary<string, Type[]> map = LifeCycleConfigs.MethodTypes;
            int count = map.Count;

            for (int index = 0; index < count; index++)
            {
                string lifeCycleName = map.GetKey(index);
                Type[] lifeCycleParams = map.Get(index);
                MethodInfo methodInfo = DLLManager.Instance.GetMethod(classFullName, lifeCycleName, lifeCycleParams);
                if (methodInfo != null)
                {
                    Type type = Type.GetType($"Fusion.Hotfix.Mono.LifeCycle.{lifeCycleName}LifeCycle, Fusion.Hotfix.Runtime");
                    DLLMonoLifeCycle dllMonoLifeCycle = gameObject.AddComponent(type) as DLLMonoLifeCycle;
                    dllMonoLifeCycle.MonoName = classFullName;
                    dllMonoLifeCycle.Register(monoBase, methodInfo);
                    dllMonoLifeCycle.enabled = enabled;
                    lifeCycleMap[lifeCycleName] = dllMonoLifeCycle;
                }
            }
        }
    }
}
